package com.wust.modules.poi.word.parse;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.wust.modules.poi.cache.WordCache;
import com.wust.modules.poi.util.PoiPublicUtil;
import com.wust.modules.poi.word.entity.MyXWPFDocument;
import com.wust.modules.poi.word.entity.WordImageEntity;
import com.wust.modules.poi.word.entity.params.ExcelListEntity;
import com.wust.modules.poi.word.parse.excel.ExcelEntityParse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFFooter;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import com.wust.modules.poi.word.parse.excel.ExcelMapParse;

@Slf4j
public class ParseWord07 {

    private void addAnImage(WordImageEntity obj, XWPFRun currentRun) throws Exception {
        Object[] isAndType = PoiPublicUtil.getIsAndType(obj);

        try {
            String picId = currentRun.getParagraph().getDocument().addPictureData((byte[])((byte[])isAndType[0]), (Integer)isAndType[1]);
            ((MyXWPFDocument)currentRun.getParagraph().getDocument()).createPicture(currentRun, picId, currentRun.getParagraph().getDocument().getNextPicNameNumber((Integer)isAndType[1]), obj.getWidth(), obj.getHeight());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

    private void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText, List<Integer> runIndex, Map<String, Object> map) throws Exception {
        Object obj = PoiPublicUtil.getRealValue(currentText, map);
        if (obj instanceof WordImageEntity) {
            currentRun.setText("", 0);
            this.addAnImage((WordImageEntity)obj, currentRun);
        } else {
            currentText = obj.toString();
            currentRun.setText(currentText, 0);
        }

        for (Integer index : runIndex) {
            paragraph.getRuns().get(index).setText("", 0);
        }

        runIndex.clear();
    }

    private Object checkThisTableIsNeedIterator(XWPFTableCell cell, Map<String, Object> map) throws Exception {
        String text = cell.getText().trim();
        return text.startsWith("{{") && text.endsWith("}}") && text.contains("in ") ? PoiPublicUtil.getRealValue(text.replace("in ", "").trim(), map) : null;
    }

    private void parseAllParagraphic(List<XWPFParagraph> paragraphs, Map<String, Object> map) throws Exception {
        for(int i = 0; i < paragraphs.size(); ++i) {
            XWPFParagraph paragraph = paragraphs.get(i);
            if (paragraph.getText().contains("{{")) {
                this.parseThisParagraph(paragraph, map);
            }
        }

    }

    private void parseThisParagraph(XWPFParagraph paragraph, Map<String, Object> map) throws Exception {
        XWPFRun currentRun = null;
        String currentText = "";
        Boolean isfinde = false;
        List<Integer> runIndex = new ArrayList();

        for(int i = 0; i < paragraph.getRuns().size(); ++i) {
            XWPFRun run = paragraph.getRuns().get(i);
            String text = run.getText(0);
            if (!StringUtils.isEmpty(text)) {
                if (isfinde) {
                    currentText = currentText + text;
                    if (!currentText.contains("{{")) {
                        isfinde = false;
                        runIndex.clear();
                    } else {
                        runIndex.add(i);
                    }

                    if (currentText.contains("}}")) {
                        this.changeValues(paragraph, currentRun, currentText, runIndex, map);
                        currentText = "";
                        isfinde = false;
                    }
                } else if (text.contains("{")) {
                    currentText = text;
                    isfinde = true;
                    currentRun = run;
                } else {
                    currentText = "";
                }

                if (currentText.contains("}}")) {
                    this.changeValues(paragraph, currentRun, currentText, runIndex, map);
                    isfinde = false;
                }
            }
        }

    }

    private void parseThisRow(List<XWPFTableCell> cells, Map<String, Object> map) throws Exception {
        Iterator iterator = cells.iterator();

        while(iterator.hasNext()) {
            XWPFTableCell cell = (XWPFTableCell) iterator.next();
            this.parseAllParagraphic(cell.getParagraphs(), map);
        }

    }

    private void parseThisTable(XWPFTable table, Map<String, Object> map) throws Exception {
        ExcelEntityParse excelEntityParse = new ExcelEntityParse();

        for(int i = 0; i < table.getNumberOfRows(); ++i) {
            XWPFTableRow row = table.getRow(i);
            List<XWPFTableCell> cells = row.getTableCells();
            if (cells.size() == 1) {
                Object listobj = this.checkThisTableIsNeedIterator(cells.get(0), map);
                if (listobj == null) {
                    this.parseThisRow(cells, map);
                } else if (listobj instanceof ExcelListEntity) {
                    table.removeRow(i);
                    excelEntityParse.parseNextRowAndAddRow(table, i, (ExcelListEntity)listobj);
                } else {
                    table.removeRow(i);
                    ExcelMapParse.parseNextRowAndAddRow(table, i, (List)listobj);
                }
            } else {
                this.parseThisRow(cells, map);
            }
        }

    }

    public XWPFDocument parseWord(String url, Map<String, Object> map) throws Exception {
        MyXWPFDocument doc = WordCache.getXWPFDocumen(url);
        assert doc != null;
        this.parseWordSetValue(doc, map);
        return doc;
    }


    private void parseWordSetValue(MyXWPFDocument doc, Map<String, Object> map) throws Exception {
        this.parseAllParagraphic(doc.getParagraphs(), map);
        this.parseHeaderAndFoot(doc, map);
        Iterator itTable = doc.getTablesIterator();

        while(itTable.hasNext()) {
            XWPFTable table = (XWPFTable)itTable.next();
            if (table.getText().contains("{{")) {
                this.parseThisTable(table, map);
            }
        }

    }

    private void parseHeaderAndFoot(MyXWPFDocument doc, Map<String, Object> map) throws Exception {
        List<XWPFHeader> headerList = doc.getHeaderList();

        for (XWPFHeader xwpfHeader : headerList) {
            for (int i = 0; i < xwpfHeader.getListParagraph().size(); ++i) {
                this.parseThisParagraph(xwpfHeader.getListParagraph().get(i), map);
            }
        }

        List<XWPFFooter> footerList = doc.getFooterList();

        for (XWPFFooter xwpfFooter : footerList) {
            for (int i = 0; i < xwpfFooter.getListParagraph().size(); ++i) {
                this.parseThisParagraph((XWPFParagraph) xwpfFooter.getListParagraph().get(i), map);
            }
        }

    }
}
